package com.personal.system.service.impl.sys;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.personal.system.domain.AutoIncrementCode;
import com.personal.system.mapper.sys.AutoIncrementCodeMapper;
import com.personal.system.service.sys.AutoIncrementCodeService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class AutoIncrementCodeServiceImpl implements AutoIncrementCodeService {

    @Resource
    private AutoIncrementCodeMapper codeMapper;

    private Lock lock = new ReentrantLock();

    @Resource
    private RedissonClient redissonClient;

    /**
     * 生成指定前缀加后缀的 从1开始的递增编号
     * @param prefix 前缀
     * @param date   日期
     * @param digit  生成几位
     * @return
     */
    public String generateCode(String prefix, String date, int digit) throws Exception {
        RLock anyLock = redissonClient.getLock("anyLock");
        // 参数分别是：获取锁的最大等待时间(期间可重试),锁的自动释放时间,时间单位
        boolean isLock = anyLock.tryLock(1, 10, TimeUnit.SECONDS);
        if (isLock) {
            try {
                Integer lastNumber = getLastNumber(prefix, date);
                saveLastNumber(prefix, date, lastNumber);
//        String number = String.format("%0"+digit+"d", lastNumber);
                String fill = StrUtil.fillBefore(lastNumber.toString(), '0', digit);
                return prefix + date + fill;
            } finally {
                anyLock.unlock();
            }
        }
        return null;

    }

    private Integer getLastNumber(String prefix, String date) {
        LambdaQueryWrapper<AutoIncrementCode> qw = new LambdaQueryWrapper<>();
        qw.eq( AutoIncrementCode::getPrefix,prefix);
        qw.eq( AutoIncrementCode::getCreateDate,date);
        AutoIncrementCode autoCode = codeMapper.selectOne(qw);
        if (null == autoCode) return 1;

        return autoCode.getLastNum() + 1;
    }

    private void saveLastNumber(String prefix, String date, Integer lastNumber) {
        List<AutoIncrementCode> auto = codeMapper.selectList(Wrappers.lambdaQuery(AutoIncrementCode.class)
                .eq(AutoIncrementCode::getPrefix, prefix));
        if (CollUtil.isEmpty(auto)) {
            AutoIncrementCode autoIncrementCode = AutoIncrementCode.builder()
                    .prefix(prefix).createDate(date).lastNum(lastNumber).build();
            codeMapper.insert(autoIncrementCode);
        } else {
            AutoIncrementCode code = auto.get(0);
            code.setLastNum(lastNumber);
            code.setCreateDate(date);
            codeMapper.updateById(code);
        }

    }

}
